home *** CD-ROM | disk | FTP | other *** search
- /*
- File: examplecodec.c
-
- Copyright: © 1991-1996 by Apple Computer, Inc., all rights reserved.
-
- This is an example of am image compression codec that handles both
- compression and decompression of images as passed to it by the
- Image Compression manager. It is built as a Component Manager Component.
-
- The compression scheme here is 420 YUV. The image is stored as separate
- luminance and chrominance channels. For each 2x2 block of pixels in the
- source image we store 4 luminance (Y) components, 1 Y-Red component (U) and
- 1 Y-Blue (V) component. Each Y-component is stored as 6-bits, resulting in a
- savings of 2.4:1 over a 24-bit/pixel image (6*4 + 2*8)/4 = 10 bits/pixel.
-
- */
-
- #include <Memory.h>
- #include <Resources.h>
- #include <Quickdraw.h>
- #include <QDOffscreen.h>
- #include <OSUtils.h>
- #include <Errors.h>
- #include <FixMath.h>
-
- #include "ImageCodec.h"
-
- #ifndef _CreateRoutineDescriptor_
- #define _CreateRoutineDescriptor_
- #if GENERATINGPOWERPC
- #define ExternRoutineDescriptor(info, proc) \
- extern RoutineDescriptor g##proc##RD;
-
- #define CreateRoutineDescriptor(info, proc) \
- RoutineDescriptor g##proc##RD = BUILD_ROUTINE_DESCRIPTOR(info, proc);
-
- #define GetRoutineAddress(proc) (&g##proc##RD)
- #else
- #define ExternRoutineDescriptor(info, proc)
- #define CreateRoutineDescriptor(info, proc)
-
- #define GetRoutineAddress(proc) (proc)
- #endif
- #endif
-
-
- #ifdef POWERPC_NATIVE
- #pragma options align=mac68k
- #endif
-
- #ifndef NOASM
- #define NOASM 0
- #endif
-
- #ifndef DECO_BUILD
- #define DECO_BUILD 0
- #endif
-
- #ifndef COMP_BUILD
- #define COMP_BUILD 0
- #endif
-
- #if !DECO_BUILD && !COMP_BUILD
- #error "must specify either DECO_BUILD or COMP_BUILD"
- #endif
-
- #if DECO_BUILD && !defined(ASYNC_DECODE)
- #define ASYNC_DECODE 1 // if defined, use scheduled asynchronous display
- #endif
-
- #ifndef ASYNC_DECODE
- #define ASYNC_DECODE 0
- #endif
-
- #if !defined(QT_MP) && ASYNC_DECODE && defined(POWERPC_NATIVE)
- #define QT_MP 1
- #endif
-
- #ifndef QT_MP
- #define QT_MP 0
- #endif
-
- #if QT_MP && !ASYNC_DECODE
- #error "can't QT_MP without ASYNC_DECODE"
- #endif
-
- /* Version information */
-
- #define EXAMPLE_CODEC_REV 2
- #define codecInterfaceVersion 2 /* high word returned in component GetVersion */
-
-
-
- /* Some useful macros and constants */
-
- #define R_W 0x4ccd
- #define G_W 0x970a
- #define B_W 0x1c29
- #define PIN(_n) ((_n) < 0 ? 0 : (_n) > 255 ? 255 : (_n))
-
-
- /*
- Our data structure declarations
- */
-
- #if DECO_BUILD
-
- #define QUEUE_SIZE 30
-
- #ifndef fieldOffset
- #define fieldOffset(type, field) ((short) &((type *) 0)->field)
- #endif
-
- /*
- The DecompressRecord is used to store the information needed
- to decompress a frame asynchronously.
- */
- struct DecompressRecord {
- ComponentMPWorkFunctionHeaderRecord header;
- void *nextBusy; // next DecompressRecord that is queued up
- void *nextFree; // next unused DecompressRecord
- Ptr srcData; // pointer to compressed data
- Ptr baseAddr; // base address of destination PixMap
- short rowBytes; // rowBytes parameter of dest PixMap
- short width; // width (in pixels) of a row
- short numStrips; // number of strips to draw
- long srcDataIncrement; // increment for srcData between strips
- long baseAddrIncrement; // increment for baseAddr between strips
- Boolean shieldCursor; // if we need to shield the cursor
- Boolean inQueue;
- ICMCompletionProcRecord completionProc; // completion proc record to call when done
- TimeValue frameTime; // what time to decompress this frame
- Fixed rate; // rate of movie
- long scale; // time scale
- struct Globals *glob; // pointer to our globals
- };
- typedef struct DecompressRecord DecompressRecord;
-
- #endif
-
- /* This is the structure we use to hold data used by all instances of
- this compressor and decompressor */
-
- typedef struct {
- Handle rgbwTable; /* optional encode/decode table */
- Handle giwTable; /* another optional encode/decode table */
- CodecInfo **info; /* our cached codec info structure */
- } SharedGlobals;
-
-
- /* This is the structure we use to store our global data for each instance */
-
- typedef struct {
- SharedGlobals *sharedGlob; /* pointer to instance-shared globals */
- #if ASYNC_DECODE
- QTCallBack callBack; // our call back
- QTCallBackUPP decompressCallBackUPP; // pointer to our decompress callback
- ImageSequence sequenceID;
- QHdr busyQueueHead; // queue header for queued decompress records
- QHdr freeQueueHead; // queue header for free decompress records
- DecompressRecord queue[QUEUE_SIZE]; // for queued frames
- long a5World; // A5 world for decompress callback
- Boolean queueIsRunning; // set if decompress queue is currently running
- ComponentInstance target;
- volatile short decompressCount; // keep track of frames being decompressed/compressed (should only ever hit 1)
-
- ComponentMPWorkFunctionUPP
- decompressFunction;
- void *decompressFunctionRefCon;
- #endif
- } Globals;
-
-
- #define IMAGECODEC_BASENAME() CD
- #define IMAGECODEC_GLOBALS() Globals *storage
-
- #define CALLCOMPONENT_BASENAME IMAGECODEC_BASENAME
- #define CALLCOMPONENT_GLOBALS IMAGECODEC_GLOBALS
-
- #include "ImageCodec.k.h"
- #include "Components.k.h"
-
-
-
- /* Function prototypes to keep the compiler smiling. */
-
- #if QT_MP
- Boolean TestBusy( Globals *glob );
- #endif
-
- #if COMP_BUILD
- pascal void
- CompressStrip(char *data,char *baseAddr,short rowBytes,short w,SharedGlobals *sg);
- #endif
-
- #if DECO_BUILD
- pascal void
- DecompressStrip(char *data,char *baseAddr,short rowBytes,short w,SharedGlobals *sg);
- #endif
-
- ComponentResult
- InitSharedTables(Globals *glob,ComponentInstance self);
-
- #if ASYNC_DECODE
- pascal ComponentResult DecompressWorkFunction(Globals *glob, DecompressRecord *drp);
-
- CreateRoutineDescriptor(uppComponentMPWorkFunctionProcInfo, DecompressWorkFunction)
-
- pascal void DecompressCallBack(QTCallBack cb,long refcon);
-
- CreateRoutineDescriptor(uppQTCallBackProcInfo, DecompressCallBack)
- #endif
-
-
- /************************************************************************************
- * This is the main dispatcher for our codec. All calls from the codec manager
- * will come through here, with a unique selector and corresponding parameter block.
- *
- * This routine must be first in the code segment of the codec component.
- */
-
- pascal ComponentResult CDComponentDispatch(ComponentParameters *params, Globals *storage);
-
- #ifdef POWERPC_NATIVE
- struct RoutineDescriptor CDComponentDispatchRD =
- BUILD_ROUTINE_DESCRIPTOR((kPascalStackBased | RESULT_SIZE (kFourByteCode) |
- STACK_ROUTINE_PARAMETER (1, kFourByteCode) |
- STACK_ROUTINE_PARAMETER (2, kFourByteCode)),CDComponentDispatch);
- #endif
-
- static ProcPtr CDFindRoutineProcPtr(short selector, ProcInfoType *procInfo);
-
- pascal ComponentResult CDComponentDispatch(ComponentParameters *params, Globals *storage)
- {
- ProcPtr theProc;
- ProcInfoType theProcInfo;
- ComponentResult result = codecUnimpErr;
-
- theProc = CDFindRoutineProcPtr(params->what, &theProcInfo);
- if (theProc)
- result = CallComponentFunctionWithStorageProcInfo((Handle)storage, params, theProc, theProcInfo);
-
- return result;
- }
-
- static ProcPtr CDFindRoutineProcPtr(short selector, ProcInfoType *procInfo)
- {
- ProcPtr aProc;
- ProcInfoType pi;
-
- #define ComponentCall(a) case kComponent##a##Select: aProc = (ProcPtr)CD##a; pi = uppCallComponent##a##ProcInfo; break;
- #define CodecCall(a) case kImageCodec##a##Select: aProc = (ProcPtr)CD##a; pi = uppImageCodec##a##ProcInfo; break;
- #if COMP_BUILD
- #define CompressCall(a) CodecCall(a)
- #define DecompressCall(a)
- #endif
- #if DECO_BUILD
- #define CompressCall(a)
- #define DecompressCall(a) CodecCall(a)
- #endif
-
- #define ComponentError(a)
- #define DecompressError(a)
- #define CompressError(a)
-
-
- switch (selector) {
- /* the multiprocessor stuff will explode if called from 68K ... so don't let the
- MP INIT think that this code supports MP */
- #if ASYNC_DECODE && QT_MP
- ComponentCall (GetMPWorkFunction)
- #else
- ComponentError (GetMPWorkFunction)
- #endif
- ComponentError (Unregister)
- #if ASYNC_DECODE && QT_MP
- ComponentCall (Target)
- #else
- ComponentError (Target)
- #endif
- ComponentError (Register)
- ComponentCall (Version)
- ComponentCall (CanDo)
- ComponentCall (Close)
- ComponentCall (Open)
-
- CodecCall (GetCodecInfo)
-
- CompressCall (GetCompressionTime)
- CompressCall (GetMaxCompressionSize)
- CompressCall (PreCompress)
- CompressCall (BandCompress)
- DecompressCall (PreDecompress)
-
- DecompressCall (BandDecompress)
- CodecCall (Busy)
- DecompressCall (GetCompressedImageSize)
- DecompressError (GetSimilarity)
- DecompressCall (TrimImage)
-
- CompressError (RequestSettings)
- CompressError (GetSettings)
- CompressError (SetSettings)
- #if ASYNC_DECODE
- DecompressCall (Flush)
- #endif
- ComponentError (SetTimeCode)
-
- DecompressError (IsImageDescriptionEquivalent)
- ComponentError (NewMemory)
- ComponentError (DisposeMemory)
- DecompressError (HitTestData)
- ComponentError (NewImageBufferMemory)
-
- DecompressError (ExtractAndCombineFields)
-
- default:
- aProc = nil;
- pi = 0;
- }
-
- *procInfo = pi;
- return aProc;
- }
-
- /************************************************************************************
- * Return true if we can handle the selector, otherwise false.
- */
-
- pascal ComponentResult CDCanDo(Globals *storage, short selector)
- {
- #pragma unused(storage)
- ProcInfoType ignoreResult;
-
- return (CDFindRoutineProcPtr(selector,&ignoreResult) != 0);
- }
-
- /************************************************************************************
- * This gets called when the component instance is opened. We allocate our storage at this
- * point. If we have shared globals, we check if they exist, and put a pointer to them
- * in our instance globals so that other calls can get to them.
- */
-
- pascal ComponentResult CDOpen(Globals *storage, ComponentInstance self)
- {
- #pragma unused(storage)
- ComponentResult result;
- Globals *glob;
-
- /*
- First we allocate our local storage. This should store any
- kind of data used by the component instance. It should be allocated
- in the current heap.
- */
-
- if ( (glob = (Globals *)NewPtrClear(sizeof(Globals))) == nil ) {
- return(MemError());
- }
- SetComponentInstanceStorage(self,(Handle)glob);
-
- /* Check and initialize our shared globals */
-
- result = InitSharedTables(glob,self);
-
- #if ASYNC_DECODE
- /*
- if we our doing an async decode, then make a routine descriptor for our
- callback proc
- */
-
- glob->decompressCallBackUPP = GetRoutineAddress(DecompressCallBack);
-
- // Start the world with every frame queued up on the free frame list
- // and nothing queued on the busy frame list.
- {
- short i;
-
- for(i=0; i<QUEUE_SIZE; i++){
- DecompressRecord *drp = &glob->queue[i];
- Enqueue((QElem *)&drp->nextFree, &glob->freeQueueHead);
- }
- }
-
- glob->target = self;
-
- #endif
-
- return result;
- }
-
- /************************************************************************************
- * This gets called when the component instance is opened. We allocate our shared storage at this
- * point.
-
- * If we have shared globals, we check if they exist, otherwise we allocate
- * them and set the ComponentRefCon so that other instances can use them.
- *
- * The shared globals hold our CodecInfo struct, which we read from our resource file,
- * and some tables that we use for speed. If we cant get the tables we can work without
- * them. All items in the shared globals are made purgeable when the last of our
- * instances is closed. If our component was loaded in the application heap ( because
- * there was no room in the system heap) then we keep our shared storage in the app heap.
- *
- * We keep a pointer to the shared globals in our instance globals so that other calls can get to them.
- */
-
-
- ComponentResult
- InitSharedTables(Globals *glob,ComponentInstance self)
- {
- SharedGlobals *sGlob;
- long i,j,*lp;
- char *cp;
- short resFile = kResFileNotOpened;
- short oldResFile;
- THz saveZone;
- Boolean inAppHeap;
- OSErr result = noErr;
-
-
- oldResFile = CurResFile();
- saveZone = GetZone();
- inAppHeap = ( GetComponentInstanceA5(self) != 0 );
- if ( !inAppHeap )
- SetZone(SystemZone());
- if ( (sGlob=(SharedGlobals*)GetComponentRefcon((Component)self)) == nil ) {
- if ( (sGlob = (SharedGlobals*)NewPtrClear(sizeof(SharedGlobals))) == nil ) {
- result = MemError();
- goto obail;
- }
- SetComponentRefcon((Component)self,(long)sGlob);
- }
-
- glob->sharedGlob = sGlob; // keep this around where it's easy to get at
-
-
- if ( sGlob->info == nil || *(Handle)sGlob->info == nil ) {
- #if TARGET_NON_MAC
- Handle h;
- #endif
- if ( sGlob->info )
- DisposeHandle((Handle)sGlob->info);
- #if TARGET_NON_MAC
- h = (CodecInfo **)NewHandleClear(sizeof(CodecInfo));
- if (h && *h) {
- CodecInfo ci = {
- "Example - YUV", /* name of the codec TYPE ( data format ) */
- 1, /* version */
- 1, /* revision */
- OSTypeConst('appl'), /* who made this codec */
- codecInfoDoes32 + codecInfoDoesSpool, /* depth and etc. supported directly on decompress */
- codecInfoDoes32 + codecInfoDoesSpool, /* depth and etc supported directly on compress */
- codecInfoDepth16, /* which data formats do we understand */
- 100, /* compress accuracy (0-255) (relative to format) */
- 100, /* decompress accuracy (0-255) (relative to format) */
- 200, /* millisecs to compress 320x240 image on base Mac */
- 200, /* millisecs to decompress 320x240 image on base Mac */
- 100, /* compression level (0-255) (relative to format) */
- 0,
- 2, /* minimum height */
- 2, /* minimum width */
- 0,
- 0,
- 0
- };
- BlockMoveData(&ci,*h,sizeof(CodecInfo));
- } else {
- result = memFullErr;
- h=0;
- }
- sGlob->info = h;
- #else
- /* Get the CodecInfo struct which we keep in our resource fork */
-
- #ifndef LINK_EXAMPLE_CODEC
- resFile = OpenComponentResFile((Component)self);
- if (resFile == kResFileNotOpened) {
- result = memFullErr;
- goto obail;
- }
- #endif
- #ifndef POWERPC_NATIVE
- sGlob->info = (CodecInfo **) Get1Resource(codecInfoResourceType,128);
- #else
- sGlob->info = (CodecInfo **) Get1Resource(codecInfoResourceType,129);
- #endif
- if ( sGlob->info == nil ) {
- result = ResError();
- goto obail;
- }
- LoadResource((Handle)sGlob->info);
- if ( result = ResError() ) {
- goto obail;
- }
- DetachResource((Handle)sGlob->info);
- }
- #endif
- HNoPurge((Handle)sGlob->info);
-
- if ( sGlob->rgbwTable == nil || *sGlob->rgbwTable == nil ) {
- if ( sGlob->rgbwTable )
- ReallocateHandle(sGlob->rgbwTable,3*256*sizeof(long));
- else
- sGlob->rgbwTable = NewHandleSys(3*256*sizeof(long));
-
- /* we can actual still work without these tables, so we dont bail
- if we cant get the memory for them */
-
- if ( sGlob->rgbwTable && *sGlob->rgbwTable ) {
- lp = (long *)*sGlob->rgbwTable;
- for ( i=0, j = 0; i < 256; i++, j += R_W )
- *lp++ = j;
- for ( i=0, j = 0; i < 256; i++, j += G_W )
- *lp++ = j;
- for ( i=0, j = 0; i < 256; i++, j += B_W )
- *lp++ = j;
- }
- }
- if ( sGlob->rgbwTable )
- HNoPurge(sGlob->rgbwTable); /* make sure it wont get purged while we are open */
-
- /* green inverse table */
-
- if ( sGlob->giwTable == nil || *sGlob->giwTable == nil ) {
- if ( sGlob->giwTable )
- ReallocateHandle(sGlob->giwTable,256);
- else
- sGlob->giwTable = NewHandleSys(256);
-
- /* we can actual still work without these tables, so we dont bail
- if we cant get the memory for them */
-
- if ( sGlob->giwTable && *sGlob->giwTable ) {
- for ( i=0, cp = *sGlob->giwTable ; i < 256; i++ )
- *cp++ = PIN( (i<<16) / G_W);
- }
- }
- if ( sGlob->giwTable )
- HNoPurge(sGlob->giwTable); /* make sure it wont get purged while we are open */
-
-
- obail:
- #ifndef LINK_EXAMPLE_CODEC
- if (resFile != kResFileNotOpened)
- CloseComponentResFile(resFile);
- #endif
- UseResFile(oldResFile);
- SetZone(saveZone);
- if ( result != noErr && sGlob != nil ) {
- if ( sGlob->rgbwTable )
- DisposeHandle(sGlob->rgbwTable);
- if ( sGlob->info )
- DisposeHandle((Handle)sGlob->info);
- DisposePtr((Ptr)sGlob);
- SetComponentRefcon((Component)self,(long)nil);
- }
- return(result);
- }
-
- /************************************************************************************
- * This gets called when the component instance is closed. We need to get rid of any
- * instance storage here.
- */
-
- pascal ComponentResult CDClose(Globals *storage,ComponentInstance self)
- {
- SharedGlobals *sGlob;
- Globals *glob = (Globals *)storage;
-
- /* If we are closing our last instance
- then we make the shared global items purgeable to
- speed things up next instance.
- */
-
- if (glob) {
- if ( CountComponentInstances((Component)self) == 1) {
- if ( (sGlob=(SharedGlobals*)glob->sharedGlob) != nil ) {
- if ( sGlob->rgbwTable )
- HPurge(sGlob->rgbwTable);
- if ( sGlob->giwTable )
- HPurge(sGlob->giwTable);
- if ( sGlob->info )
- HPurge((Handle)sGlob->info);
- }
- }
-
- #if ASYNC_DECODE
- if (glob->callBack) {
- CDFlush((void *)glob);
- DisposeCallBack(glob->callBack);
- }
- #endif
-
- DisposePtr((Ptr)glob);
- }
- return(noErr);
- }
-
-
-
- /************************************************************************************
- * Set the target for this component.
- */
-
- #if ASYNC_DECODE
- pascal ComponentResult CDTarget(Globals *storage,ComponentInstance target)
- {
- Globals *glob = (Globals *)storage;
-
- glob->target = target;
-
- return noErr;
- }
- #endif
-
- /************************************************************************************
- * Return the version of this component ( defines interface ) and revision level
- * of the code.
- */
-
- pascal ComponentResult CDVersion(Globals *storage)
- {
- return ((codecInterfaceVersion<<16) | EXAMPLE_CODEC_REV); /* interface version in hi word, code rev in lo word */
- }
-
-
- #if COMP_BUILD
-
- /************************************************************************************
- * CDPreCompress gets called before an image is compressed, or whenever the source pixmap
- * pixel size changes when compressing a sequence. We return information about
- * how we can compress the image to the codec manager, so that it can fit the source data
- * to our requirements. The ImageDescriptor is already filled in, so we can use it for
- * reference (or even add to it ). PixelSize is the pixel depth of the source pixmap, we
- * use this as a reference for deciding what we can do. The other parameters return information
- * to the CodecManager about what we can do. We can also do setup here if we want to.
- */
-
- pascal ComponentResult CDPreCompress(Globals *storage,register CodecCompressParams *p)
- {
- CodecCapabilities *capabilities = p->capabilities;
-
- /*
- * First we return which depth input pixels we can deal with - based on what the
- * app has available - we can only work with 32 bit input pixels.
- */
-
- switch ( (*p->imageDescription)->depth ) {
- case 16:
- capabilities->wantedPixelSize = 32;
- break;
- default:
- return(codecConditionErr);
- break;
- }
-
- /* if the buffer gets banded, return the smallest one we can deal with */
-
- capabilities->bandMin = 2;
-
- /* if the buffer gets banded, return the increment it be should grown */
-
- capabilities->bandInc = 2;
-
-
- /*
- * If a codec needs the dimensions of the source pixmap to be of certain multiples
- * it can ask for the image to be extended out (via pixel replication) vertically
- * and/or horizontally.
- *
- * In our case, we're dealing with 2 by 2 blocks and therefore we want the image
- * height and width to both be multiples of 2. If either dimension is odd, we
- * ask it have it extended by one pixel.
- */
-
- capabilities->extendWidth = (*p->imageDescription)->width & 1;
- capabilities->extendHeight = (*p->imageDescription)->height & 1;
-
- return(noErr);
- }
-
-
- /************************************************************************************
- * CDBandCompress gets called when the codec manager wants us to compress an image, or a horizontal
- * band of an image. The pixel data at sBaseAddr is guaranteed to conform to the criteria we
- * demanded in BeginCompress.
- */
-
- pascal ComponentResult CDBandCompress(Globals *storage,register CodecCompressParams *p)
- {
- short width,height;
- Ptr cDataPtr,dataStart;
- short depth;
- Rect sRect;
- long offsetH,offsetV;
- Globals *glob = (Globals *)storage;
- char *baseAddr;
- long numLines,numStrips;
- short rowBytes;
- long stripBytes;
- char mmuMode = 1;
- short y;
- ImageDescription **desc = p->imageDescription;
- OSErr result = noErr;
-
- /* If there is a progress proc, give it an open call at the start of this band. */
-
- if (p->progressProcRecord.progressProc)
- CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressOpen,0,
- p->progressProcRecord.progressRefCon);
-
- width = (*desc)->width;
- height = (*desc)->height;
- depth = (*desc)->depth;
- dataStart = cDataPtr = p->data;
-
- /* figure out offset to first pixel in baseAddr from the pixelsize and bounds */
-
- rowBytes = p->srcPixMap.rowBytes & 0x3fff;
- sRect = p->srcPixMap.bounds;
- numLines = p->stopLine - p->startLine; /* number of scanlines in this band */
- numStrips = (numLines+1)>>1; /* number of strips in this band */
- stripBytes = ((width+1)>>1) * 5;
-
- /* adjust the source baseAddress to be at the beginning of the desired rect */
-
- switch ( p->srcPixMap.pixelSize ) {
- case 32:
- offsetH = sRect.left<<2;
- break;
- case 16:
- offsetH = sRect.left<<1;
- break;
- case 8:
- offsetH = sRect.left;
- break;
- default:
- result = codecErr;
- goto bail;
- }
- offsetV = sRect.top * rowBytes;
- baseAddr = p->srcPixMap.baseAddr + offsetH + offsetV;
-
-
- /* if there is not a flush proc, adjust the pointer to the next band */
-
- if ( p->flushProcRecord.flushProc == nil )
- cDataPtr += (p->startLine>>1) * stripBytes;
- else {
- if ( p->bufferSize < stripBytes ) {
- result = codecSpoolErr;
- goto bail;
- }
- }
-
-
- /* do the slower flush/progress case if we have too */
-
- if ( p->flushProcRecord.flushProc || p->progressProcRecord.progressProc ) {
- SharedGlobals *sg = glob->sharedGlob;
-
-
- for ( y=0; y < numStrips; y++) {
- SwapMMUMode(&mmuMode);
- CompressStrip(cDataPtr,baseAddr,rowBytes,width,sg);
- SwapMMUMode(&mmuMode);
- baseAddr += rowBytes<<1;
- if ( p->flushProcRecord.flushProc ) {
- if ( (result=CallICMFlushProc(p->flushProcRecord.flushProc,cDataPtr,stripBytes,
- p->flushProcRecord.flushRefCon)) != noErr) {
- result = codecSpoolErr;
- goto bail;
- }
- } else {
- cDataPtr += stripBytes;
- }
- if (p->progressProcRecord.progressProc) {
- if ( (result=CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressUpdatePercent,
- FixDiv(y,numStrips),p->progressProcRecord.progressRefCon)) != noErr ) {
- result = codecAbortErr;
- goto bail;
- }
- }
- }
- } else {
- SharedGlobals *sg = glob->sharedGlob;
- short tRowBytes = rowBytes<<1;
-
- SwapMMUMode(&mmuMode);
- for ( y=numStrips; y--; ) {
- CompressStrip(cDataPtr,baseAddr,rowBytes,width,sg);
- cDataPtr += stripBytes;
- baseAddr += tRowBytes;
- }
- SwapMMUMode(&mmuMode);
- }
-
- /*
-
- return size and similarity on the last band
-
- */
-
- if ( p->conditionFlags & codecConditionLastBand ) {
- (*p->imageDescription)->dataSize = stripBytes * ((height+1)>>1); /* return the actual size of the compressed data */
- p->similarity = 0; /* we don't do frame differencing */
- }
-
- bail:
- /* If there is a progress proc, give it a close call at the end of this band. */
-
- if (p->progressProcRecord.progressProc)
- CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressClose,0,
- p->progressProcRecord.progressRefCon);
-
- return(result);
- }
-
- #endif
-
- pascal ComponentResult CDBusy(Globals *storage, ImageSequence seq)
- {
- #pragma unused(seq)
- #if ASYNC_DECODE && QT_MP
- // and return true if there is still something goin' on
- return TestBusy( (Globals *)storage );
- #else
- return 0;
- #endif
- }
-
- #if ASYNC_DECODE
-
- /*
- CDFlush is called when the image compression manager wants the
- codec to empty its schedule queue. An example would be when a movie is
- playing and the user moves the thumb. The sudden jump in time renders
- any previously scheduled frames useless. So we need to flush the queue so
- we can start over.
- */
- pascal ComponentResult CDFlush(Globals *storage)
- {
- Globals *glob = (Globals *)storage;
-
- /*
- if there's not a callback proc allocated, we sure don't have any frames
- queued up.
- */
- if (glob->callBack) {
- DecompressRecord *drp;
- long saveA5 = SetA5(glob->a5World);
-
- glob->queueIsRunning = false; // flag queue as not running.
- // otherwise, we'll never start it up again
-
- // kill the callback
- CancelCallBack(glob->callBack);
-
- #if QT_MP
- // wait for things to stop
- while( TestBusy( glob ) )
- ;
- #endif
-
- // tear down the queue
- while (drp = (DecompressRecord *)glob->busyQueueHead.qHead) {
- drp = (DecompressRecord *)(((long)drp) - fieldOffset(DecompressRecord, nextBusy));
- Dequeue((QElem *)&drp->nextBusy, &glob->busyQueueHead);
-
- if (drp->srcData) {
- // call back to say we're done
- ICMDecompressComplete(glob->sequenceID, -1, codecCompletionSource | codecCompletionDest, &drp->completionProc);
- Enqueue((QElem *)&drp->nextFree, &glob->freeQueueHead);
- drp->srcData = nil;
- }
- }
-
- SetA5(saveA5);
- }
-
- return (noErr);
- }
-
- #if QT_MP
- pascal ComponentResult CDGetMPWorkFunction(Globals *storage, ComponentMPWorkFunctionUPP *workFunction, void **refCon)
- {
- Globals *glob = (Globals *)storage;
-
- *workFunction = (ComponentMPWorkFunctionUPP)GetRoutineAddress(DecompressWorkFunction);
- *refCon = storage;
-
- return noErr;
- }
- #endif // QT_MP
-
- #endif // ASYNC_DECODE
-
-
- #if DECO_BUILD
-
-
- /************************************************************************************
- * CDPreDecompress gets called before an image is decompressed. We return information about
- * how we can decompress the image to the codec manager, so that it can fit the destination data
- * to our requirements.
- */
-
- pascal ComponentResult CDPreDecompress(Globals *storage,register CodecDecompressParams *p)
- {
- Globals *glob = (Globals *)storage;
- register CodecCapabilities *capabilities = p->capabilities;
-
- /* Decide which depth compressed data we can deal with. */
-
- switch ( (*p->imageDescription)->depth ) {
- case 16:
- break;
- default:
- return(codecConditionErr);
- break;
- }
-
- /* We can deal only 32 bit pixels. */
-
- capabilities->wantedPixelSize = 32;
-
- /* The smallest possible band we can do is 2 scan lines. */
-
- capabilities->bandMin = 2;
-
- /* We can deal with 2 scan line high bands. */
-
- capabilities->bandInc = 2;
-
- /* If we needed our pixels to be aligned on some integer multiple we would set these to
- * the number of pixels we need the dest extended by. If we dont care, or we take care of
- * it ourselves we set them to zero.
- */
-
- capabilities->extendWidth = p->srcRect.right & 1;
- capabilities->extendHeight = p->srcRect.bottom & 1;
- #if ASYNC_DECODE
- if (glob->decompressFunction == nil) {
- #if QT_MP
- CallComponentGetMPWorkFunction(glob->target, &glob->decompressFunction, &glob->decompressFunctionRefCon);
- #else
- glob->decompressFunction = (ComponentMPWorkFunctionUPP)GetRoutineAddress(DecompressWorkFunction);
- glob->decompressFunctionRefCon = glob;
- #endif
- }
-
- capabilities->flags = codecCanAsyncWhen | codecCanAsync | codecCanShieldCursor;
- glob->sequenceID = p->sequenceID;
- #else
- capabilities->flags = 0;
- #endif
- return(noErr);
- }
-
- #if ASYNC_DECODE
-
- pascal ComponentResult DecompressWorkFunction(Globals *glob, DecompressRecord *drp)
- {
- if (drp->header.workFlags & mpWorkFlagGetProcessorCount)
- drp->header.processorCount = 1;
-
- if (drp->header.workFlags & mpWorkFlagDoWork) {
- short y;
- char mmuMode = true32b; // we want to be in 32-bit mode
- Ptr cDataPtr = drp->srcData; // compressed data pointer;
- Ptr baseAddr = drp->baseAddr; // base address of dest PixMap;
-
- SwapMMUMode(&mmuMode); // put us in 32-bit mode
- for ( y=drp->numStrips; y--; ) {
- DecompressStrip(cDataPtr,baseAddr,drp->rowBytes,drp->width,glob->sharedGlob);
- baseAddr += drp->baseAddrIncrement;
- cDataPtr += drp->srcDataIncrement;
- }
- SwapMMUMode(&mmuMode); // back to our old memory mode
- }
-
- if (drp->header.workFlags & mpWorkFlagDoCompletion) {
- glob->decompressCount--;
-
- ICMDecompressComplete(glob->sequenceID, noErr, codecCompletionSource | codecCompletionDest, &drp->completionProc);
-
- drp->srcData = nil;
-
- if (drp->inQueue) {
- Dequeue((void *)&drp->nextBusy, &glob->busyQueueHead);
- Enqueue((void *)&drp->nextFree, &glob->freeQueueHead);
-
- // queue up the next one
- if (glob->queueIsRunning && (drp = (void *)glob->busyQueueHead.qHead)) {
- drp = (void *)((Ptr)drp - (Ptr)fieldOffset(DecompressRecord, nextBusy));
- CallMeWhen(
- glob->callBack,
- glob->decompressCallBackUPP,
- (long)drp,
- (drp->rate >= 0) ? triggerTimeFwd : triggerTimeBwd,
- (long)drp->frameTime,
- (long)drp->scale);
- }
- else {
- glob->queueIsRunning = false;
- }
- }
- }
-
- return noErr;
- }
-
- /*
- This is the call back proc that is used for scheduled asynchronously displayed
- frames. It is called at the scheduled frame time, and should display that
- frame. If there is a frame queued up after this one, it should be scheduled.
- */
- pascal void DecompressCallBack(QTCallBack cb,long refcon)
- {
- DecompressRecord *drp = (DecompressRecord *)refcon;
- Globals *glob = (Globals *)drp->glob;
-
- if (drp->srcData) {
- if (drp->shieldCursor) {
- ICMShieldSequenceCursor(glob->sequenceID);
- drp->shieldCursor = false;
- }
-
- drp->header.headerSize = sizeof(ComponentMPWorkFunctionHeaderRecord);
- drp->header.recordSize = sizeof(DecompressRecord);
- drp->header.workFlags = mpWorkFlagDoWork | mpWorkFlagDoCompletion;
- if (!drp->inQueue)
- drp->header.workFlags |= mpWorkFlagCopyWorkBlock;
-
- glob->decompressCount++;
- CallComponentMPWorkFunctionProc(glob->decompressFunction, glob->decompressFunctionRefCon, (void *)drp);
- }
- }
-
- #endif
-
-
- /************************************************************************************
- * CDBandDecompress gets called when the codec manager wants us to decompress an image or a horizontal
- * band of an image. The pixel data at baseAddr is guaranteed to conform to the criteria we
- * demanded in BeginDecompress. If maskIn is true, then the mask data at mBaseAddr is valid, and
- * we need to clear bits in it that correspond to any pixels in the destination we do not want to
- * change. ( We always write all pixels, so we dont care. This mode is important only for those
- * codecs that have frame differencing and don't always write all the pixels. )
- */
-
- pascal ComponentResult CDBandDecompress(Globals *storage,register CodecDecompressParams *p)
- {
- long offsetH,offsetV;
- Globals *glob = (Globals *)storage;
- long numLines,numStrips;
- short rowBytes;
- long stripBytes;
- short width;
- short y;
- char *baseAddr;
- char *cDataPtr;
- char mmuMode = 1;
- OSErr result = noErr;
-
- /* If there is a progress proc, give it an open call at the start of this band. */
-
- if (p->progressProcRecord.progressProc)
- CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressOpen,0,
- p->progressProcRecord.progressRefCon);
-
-
-
- /* initialize some local variables */
-
- width = (*p->imageDescription)->width;
- rowBytes = p->dstPixMap.rowBytes;
- numLines = p->stopLine - p->startLine; /* number of scanlines in this band */
- numStrips = (numLines+1)>>1; /* number of strips in this band */
- stripBytes = ((width+1)>>1) * 5; /* number of bytes in one strip of blocks */
- cDataPtr = p->data;
-
- /* adjust the destination baseaddress to be at the beginning of the desired rect */
-
- offsetH = (p->dstRect.left - p->dstPixMap.bounds.left);
- offsetH <<=2; /* 1 pixel = 4 bytes */
- offsetV = (p->dstRect.top - p->dstPixMap.bounds.top) * rowBytes;
- baseAddr = p->dstPixMap.baseAddr + offsetH + offsetV;
-
-
- /*
- * If we are skipping some data, we just skip it here. We can tell because
- * firstBandInFrame says this is the first band for a new frame, and
- * if startLine is not zero, then that many lines were clipped out.
- */
-
- if ( (p->conditionFlags & codecConditionFirstBand) && p->startLine != 0 ) {
- if ( p->dataProcRecord.dataProc ) {
- for ( y=0; y < p->startLine>>1; y++ ) {
- if ( (result=CallICMDataProc(p->dataProcRecord.dataProc,&cDataPtr,stripBytes,
- p->dataProcRecord.dataRefCon)) != noErr ) {
- result = codecSpoolErr;
- goto bail;
- }
- cDataPtr += stripBytes;
- }
- } else
- cDataPtr += (p->startLine>>1) * stripBytes;
- }
-
- /*
- * If theres a dataproc spooling the data to us, then we have to do the data
- * in whatever size chunks they want to give us, or if there is a progressProc
- * make sure to call it as we go along.
- */
-
- if ( p->dataProcRecord.dataProc || p->progressProcRecord.progressProc ) {
- SharedGlobals *sg = glob->sharedGlob;
-
- #if ASYNC_DECODE
- if (p->conditionFlags & codecConditionDoCursor)
- ICMShieldSequenceCursor(p->sequenceID);
- #endif
-
- for (y=0; y < numStrips; y++) {
- if (p->dataProcRecord.dataProc) {
- if ( (result=CallICMDataProc(p->dataProcRecord.dataProc,&cDataPtr,stripBytes,
- p->dataProcRecord.dataRefCon)) != noErr ) {
- result = codecSpoolErr;
- goto bail;
- }
- }
- SwapMMUMode(&mmuMode);
- DecompressStrip(cDataPtr,baseAddr,rowBytes,width,sg);
- SwapMMUMode(&mmuMode);
- baseAddr += rowBytes<<1;
- cDataPtr += stripBytes;
- if (p->progressProcRecord.progressProc) {
- if ( (result=CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressUpdatePercent,
- FixDiv(y, numStrips),p->progressProcRecord.progressRefCon)) != noErr ) {
- result = codecAbortErr;
- goto bail;
- }
- }
- }
- ICMDecompressComplete(p->sequenceID, noErr, codecCompletionSource | codecCompletionDest, &p->completionProcRecord);
-
- /*
- *
- * otherwise - do the fast case.
- *
- */
-
- } else {
- DecompressRecord stackDecompressRecord;
- DecompressRecord *drp = &stackDecompressRecord;
-
- #if ASYNC_DECODE
- if (p->frameTime) {
- if (!glob->freeQueueHead.qHead) {
- result = codecCantQueueErr;
- errorReturn:
- ICMDecompressComplete(p->sequenceID, result, codecCompletionSource | codecCompletionDest, &p->completionProcRecord);
- goto bail;
- }
-
- if (!glob->callBack) {
- // there is no current callback. allocate one.
- glob->callBack = NewCallBack(p->frameTime->base,callBackAtTime + callBackAtInterrupt + callBackAtDeferredTask);
- if (!glob->callBack) {
- result = codecCantQueueErr;
- goto errorReturn;
- }
- glob->a5World = SetA5(0);
- SetA5(glob->a5World); // is there a way to get a5 without changing it?
- }
- drp = (void *)((Ptr)glob->freeQueueHead.qHead - (Ptr)fieldOffset(DecompressRecord, nextFree));
- Dequeue((void *)&drp->nextFree, &glob->freeQueueHead);
- }
- #endif // ASYNC_DECODE
-
- drp->srcData = cDataPtr;
- drp->baseAddr = baseAddr;
- drp->rowBytes = rowBytes;
- drp->width = width;
- drp->numStrips = numStrips;
- drp->srcDataIncrement = stripBytes;
- drp->baseAddrIncrement = rowBytes<<1;
- drp->completionProc = p->completionProcRecord;
- drp->frameTime = p->frameTime->value.lo;
- drp->scale = p->frameTime->scale;
- drp->rate = p->frameTime->rate;
- drp->shieldCursor = (p->conditionFlags & codecConditionDoCursor) != 0;
- drp->glob = (void *)glob;
-
-
- #if ASYNC_DECODE
- glob->sequenceID = p->sequenceID;
-
- if (p->frameTime) {
- drp->inQueue = true;
- Enqueue((void *)(&drp->nextBusy), &glob->busyQueueHead); // put the frame in the queue
- if (!glob->queueIsRunning) {
- // the queue isn't running... start it up
- glob->queueIsRunning = true; // since CallMeWhen could be considered "CallMeRightNow"
- if (result = CallMeWhen(
- glob->callBack,
- glob->decompressCallBackUPP,
- (long)drp,
- (drp->rate >= 0) ? triggerTimeFwd : triggerTimeBwd,
- (long)drp->frameTime,
- (long)drp->scale)) {
- // there was an error
- glob->queueIsRunning = false; // if error, queue isn't running
- drp->srcData = nil;
- Dequeue((void *)&drp->nextBusy, &glob->busyQueueHead);
- Enqueue((void *)&drp->nextFree, &glob->freeQueueHead);
- goto errorReturn;
- }
- }
- }
- else
- #endif // ASYNC_DECODE
- {
- drp->inQueue = false;
-
- DecompressCallBack(nil, (long)drp);
- cDataPtr += *(long *)p->data & 0x00FFFFFF;
- }
- }
-
- /*
- *
- * IMPORTANT: update pointer to data in params, so when we get the next
- * band we'll be at the right place in our data.
- *
- */
-
- p->data = cDataPtr;
-
- if ( p->conditionFlags & codecConditionLastBand ) {
- /* Tie up any loose ends on the last band of the frame, if we had any */
- }
-
- bail:
- /* If there is a progress proc, give it a close call at the end of this band. */
-
- if (p->progressProcRecord.progressProc)
- CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressClose,0,
- p->progressProcRecord.progressRefCon);
-
- return result;
- }
-
- #endif // DECO_BUILD
-
- /************************************************************************************
- * CDGetCodecInfo allows us to return information about ourselves to the codec manager.
- *
- * There will be a tool for determining appropriate values for the accuracy, speed
- * and level information. For now we estimate with scientific wild guessing.
- *
- * The info is stored as a resource in the same file with our component.
- */
-
- pascal ComponentResult CDGetCodecInfo(Globals *storage,CodecInfo *info)
- {
- Globals *glob = (Globals *)storage;
-
- if ( info == nil )
- return(paramErr);
- BlockMoveData((Ptr)*(glob->sharedGlob)->info,(Ptr)info,sizeof(CodecInfo));
- return(noErr);
- }
-
-
- #if DECO_BUILD
- /************************************************************************************
- * When CDGetCompressedImageSize is called, we return the size in bytes of the given compressed
- * data ( for one image frame).
- */
-
- pascal ComponentResult CDGetCompressedImageSize(Globals *storage,ImageDescriptionHandle desc,Ptr data,
- long dataSize, ICMDataProcRecordPtr dataProc,long *size)
- {
- #pragma unused(storage,data,dataSize,dataProc)
-
- short width =(*desc)->width;
- short height = (*desc)->height;
-
- if ( size == nil )
- return(paramErr);
-
- /*
- * Our data has a size which is deterministic based on the image size. If it were not we
- * could encode the size in the compressed data, or figure it out by walking the
- * compressed data.
- */
-
- *size = ((width+1)/2) * 5 * ((height+1)/2);
- return(noErr);
- }
- #endif // DECO_BUILD
-
- #if COMP_BUILD
- /************************************************************************************
- * When CDGetMaxCompressionSize is called, we return the maximum size the compressed data for
- * the given image would be in bytes.
- */
-
- pascal ComponentResult CDGetMaxCompressionSize(Globals *storage,PixMapHandle src,
- const Rect *srcRect,short depth, CodecQ quality,long *size)
- {
- #pragma unused(storage,src,depth,quality)
-
- short width = srcRect->right - srcRect->left;
- short height = srcRect->bottom - srcRect->top;
-
- /* we always end up with a fixed size. If we did not, we would return the worst case size */
-
- *size = ((width+1)/2) * 5 * ((height+1)/2);
-
- return(noErr);
- }
-
-
- /************************************************************************************
- * When CDGetCompressionTime is called, we return the approximate time for compressing
- * the given image would be in milliseconds. We also return the closest actual quality
- * we can handle for the requested value.
- */
-
- pascal ComponentResult CDGetCompressionTime(Globals *storage,PixMapHandle src,
- const Rect *srcRect,short depth,CodecQ *spatialQuality,CodecQ *temporalQuality,
- unsigned long *time)
- {
- #pragma unused(storage,src,srcRect,depth)
-
- if (time)
- *time = 0; /* we don't know how many msecs */
-
- if (spatialQuality)
- *spatialQuality = codecNormalQuality; /* we have only one quality level for now */
-
- if (temporalQuality)
- *temporalQuality = 0; /* we cannot do temporal compression */
-
- return(noErr);
- }
-
- #endif // COMP_BUILD
-
- #if DECO_BUILD
-
- /************************************************************************************
- * When CDTrimImage is called, we take the given compressed data and return only the portion
- * which is represented by the trimRect. We can return a little more if we have too, but we
- * need only return enough so that the image in trimRect is properly displayed. We then
- * adjust the rectangle to corresond to the same rectangle in the new trimmed data.
- */
-
- pascal ComponentResult CDTrimImage(Globals *storage,ImageDescriptionHandle desc,Ptr inData,
- long inDataSize,ICMDataProcRecordPtr dataProc,Ptr outData,long outDataSize,
- ICMFlushProcRecordPtr flushProc,Rect *trimRect,ICMProgressProcRecordPtr progressProc)
- {
- #pragma unused(storage)
-
- Rect rect = *trimRect;
- char *dataP,*odP,*startP;
- short trimOffTop;
- short trimOffBottom;
- short trimOffLeft;
- short trimOffRight;
- short bytesOffLeft;
- short newHeight,newWidth;
- long size;
- short stripBytes;
- short newStripBytes;
- short i,y;
- OSErr result = noErr;
-
-
- if ( dataProc->dataProc == nil )
- dataProc = nil;
- if ( flushProc->flushProc == nil )
- flushProc = nil;
- if ( progressProc->progressProc == nil )
- progressProc = nil;
- if ( progressProc )
- CallICMProgressProc(progressProc->progressProc,codecProgressOpen,0,progressProc->progressRefCon);
-
- dataP = inData;
- newHeight = (*desc)->height;
- newWidth = (*desc)->width;
- stripBytes = ((newWidth+1)>>1) * 5; /* the number of bytes in a strip (2-scanlines/strip) */
-
- /* figure out how many 2x2 blocks we want to strip from each side of the image */
-
- trimOffTop = rect.top>>1;
- trimOffBottom = (newHeight - rect.bottom) >> 1;
- trimOffLeft = rect.left>>1;
- trimOffRight = (newWidth - rect.right) >> 1;
-
- /* point to the start of the first strip we are using */
-
- startP = dataP + stripBytes * trimOffTop;
-
-
- /* make the trim values pixel based */
-
- trimOffLeft <<= 1;
- trimOffTop <<= 1;
- trimOffBottom <<= 1;
- trimOffRight <<= 1;
-
- /* calculate new height and width */
-
- newHeight -= trimOffTop + trimOffBottom;
- newWidth -= trimOffLeft + trimOffRight;
-
- /* calc size in bytes of strips of the new width */
-
- newStripBytes = ((newWidth+1)>>1) * 5;
-
- /* figure number of bytes to toss at the beginning of each strip */
-
- bytesOffLeft = (trimOffLeft>>1) * 5;
-
- /* figure size of new trimmed image */
-
- size = newStripBytes * (newHeight>>1);
-
- /* make sure it's gonna fit */
-
- if ( size > outDataSize ) {
- result = codecErr;
- goto bail;
- }
-
- /* now go through the strips and copy the needed portion of each to the new data */
-
- if ( dataProc ) {
- short rightBytes = stripBytes - newStripBytes - bytesOffLeft;
- for ( y=0; y < trimOffTop; y++ ) {
- if ( (result=CallICMDataProc(dataProc->dataProc,&inData,stripBytes,dataProc->dataRefCon)) != noErr )
- goto bail;
- inData += stripBytes;
- if (progressProc ) {
- if ( (result=CallICMProgressProc(progressProc->progressProc,codecProgressUpdatePercent,
- FixDiv(y, (*desc)->height),progressProc->progressRefCon)) != noErr) {
- result = codecAbortErr;
- goto bail;
- }
- }
- }
- for ( y=0; y < newHeight; y+= 2) {
- if ( bytesOffLeft ) {
- if ( (result=CallICMDataProc(dataProc->dataProc,&inData,bytesOffLeft,dataProc->dataRefCon)) != noErr )
- goto bail;
- inData += bytesOffLeft;
- }
- if ( (result=CallICMDataProc(dataProc->dataProc,&inData,newStripBytes,dataProc->dataRefCon)) != noErr )
- goto bail;
- if ( flushProc ) {
- if ( (result=CallICMFlushProc(flushProc->flushProc,inData,newStripBytes,flushProc->flushRefCon)) != noErr ) {
- result = codecSpoolErr;
- goto bail;
- }
- }
- else {
- BlockMoveData(inData,outData,newStripBytes);
- outData += newStripBytes;
- }
- inData += newStripBytes;
- if ( rightBytes ) {
- if ( (result=CallICMDataProc(dataProc->dataProc,&inData,rightBytes,dataProc->dataRefCon)) != noErr ) {
- result = codecSpoolErr;
- goto bail;
- }
- inData += rightBytes;
- }
- if (progressProc) {
- if ( (result=CallICMProgressProc(progressProc->progressProc,codecProgressUpdatePercent,
- FixDiv((trimOffTop + y),(*desc)->height),progressProc->progressRefCon)) != noErr ) {
- result = codecAbortErr;
- goto bail;
- }
- }
- }
- }
- else {
- inData += stripBytes * trimOffTop;
- for ( y=0; y < newHeight; y += 2, inData += stripBytes) {
- if ( flushProc ) {
- if ( (result=CallICMFlushProc(flushProc->flushProc,inData + bytesOffLeft,newStripBytes,flushProc->flushRefCon)) != noErr ) {
- result = codecSpoolErr;
- goto bail;
- }
- }
- else {
- BlockMoveData(inData + bytesOffLeft,outData,newStripBytes);
- outData += newStripBytes;
- }
- if (progressProc ) {
- if ( (result=CallICMProgressProc(progressProc->progressProc,codecProgressUpdatePercent,
- FixDiv((trimOffTop + y),(*desc)->height),progressProc->progressRefCon)) != noErr ) {
- result = codecAbortErr;
- goto bail;
- }
- }
- }
- }
-
- /* adjust the rectangle to reflect our changes */
-
- trimRect->top -= trimOffTop;
- trimRect->bottom -= trimOffTop;
- trimRect->left -= trimOffLeft;
- trimRect->right -= trimOffLeft;
-
- /* return the new width and height in the image description and the size */
-
- (*desc)->height = newHeight;
- (*desc)->width = newWidth;
- (*desc)->dataSize = size;
- bail:
- if ( progressProc )
- CallICMProgressProc(progressProc->progressProc,codecProgressClose,0,progressProc->progressRefCon);
-
- return(result);
-
-
- }
- #endif // DECO_BUILD
-
- #if NOASM /* we could do this part in assembly for speed if we desired */
-
- #if COMP_BUILD
-
- #define READPIXEL(n) \
- l = *lp++; \
- r = (l>>16); \
- g = (l>>8); \
- b = l; \
- yt = (R_W*r + G_W*g + B_W*b); \
- if ( yt > ((256L<<16)-1) ) yt = ((256L<<16)-1); \
- ys[n] = yt>>16; \
- y += yt; \
- u += r; \
- v += b;
-
- #define READPIXEL_TAB(n) \
- l = *lp++; \
- r = (l>>16); \
- g = (l>>8); \
- b = l; \
- yt = (rwTable[r] + gwTable[g] + bwTable[b]); \
- if ( yt > ((256L<<16)-1) ) yt = ((256L<<16)-1); \
- ys[n] = yt>>16; \
- y += yt; \
- u += r; \
- v += b;
-
-
- pascal void
- CompressStrip(char *data,char *baseAddr,short rowBytes,short len,SharedGlobals *sg)
- {
-
- register long l,*lp = (long *)baseAddr;
- register unsigned char r,g,b;
- unsigned char ys[4];
- register long y,yt;
- short u,v;
- short rowLongs = (rowBytes>>2);
-
-
-
-
- len++;
- len>>=1;
-
- if ( sg->rgbwTable && *sg->rgbwTable ) {
- long *rwTable,*gwTable,*bwTable;
-
- rwTable = (long *)*sg->rgbwTable;
- gwTable = rwTable + 256;
- bwTable = rwTable + 512;
-
- while ( len-- > 0) {
- y = u = v = 0;
- READPIXEL_TAB(0);
- READPIXEL_TAB(1);
- lp += rowLongs-2;
- READPIXEL_TAB(2);
- READPIXEL_TAB(3);
- lp -= rowLongs;
-
- y >>= 16;
- u = (u - y)>>4;
- v = (v - y)>>4;
-
- l = (long)(0xfc & (ys[0])) << 24;
- l |= (long)(0xfc & (ys[1])) << 18;
- l |= (long)(0xfc & (ys[2])) << 12;
- l |= (long)(0xfc & (ys[3])) << 6;
- l |= u & 0xff;
- *(long *)data = MyEndian32(l);
- data += sizeof(long);
- *data++ = v;
- }
- } else {
- while ( len-- > 0) {
- y = u = v = 0;
- READPIXEL(0);
- READPIXEL(1);
- lp += rowLongs-2;
- READPIXEL(2);
- READPIXEL(3);
- lp -= rowLongs;
-
- y >>= 16;
- u = (u - y)>>4;
- v = (v - y)>>4;
-
- l = (long)(0xfc & (ys[0])) << 24;
- l |= (long)(0xfc & (ys[1])) << 18;
- l |= (long)(0xfc & (ys[2])) << 12;
- l |= (long)(0xfc & (ys[3])) << 6;
- l |= u & 0xff;
- *(long *)data = MyEndian32(l);
- data += sizeof(long);
- *data++ = v;
- }
- }
- }
-
- #endif // COMP_BUILD
-
- #if DECO_BUILD
- #define WRITEPIXEL \
- r = PIN(u+y); \
- b = PIN(v+y); \
- y <<= 16; \
- y -= r * R_W; \
- y -= b * B_W; \
- g = PIN(y / G_W); \
- *lp++ = (long) ( (long) r <<16) | ( (long) g <<8) | b;
-
- #define WRITEPIXEL_TAB \
- r = PIN(u+y); \
- b = PIN(v+y); \
- y <<= 16; \
- y -= rwTable[r]; \
- y -= bwTable[b]; \
- g = giwTable[PIN(y>>16)]; \
- *lp++ = (long) ( (long) r <<16) | ( (long) g <<8) | b;
-
- pascal void
- DecompressStrip(char *data,char *baseAddr,short rowBytes,short len,SharedGlobals *sg)
- {
- register long y;
- register unsigned char r,g,b;
- register long l,*lp;
- long u,v;
- unsigned char ys[4];
- short rowLongs = (rowBytes>>2);
- short blen = len;
-
- lp = (long *)baseAddr;
- blen++;
- blen >>= 1;
-
- if ( sg->rgbwTable && *sg->rgbwTable && sg->giwTable && *sg->giwTable ) {
- unsigned char *giwTable;
- long *rwTable,*bwTable;
-
- giwTable = (unsigned char *)(*sg->giwTable);
- rwTable = (long *)*sg->rgbwTable;
- bwTable = rwTable + 512;
- while ( blen-- > 0 ) {
- l = MyEndian32(*(long *)data);
- data += sizeof(long);
- ys[0] = (0xfc & (l>>24));
- ys[1] = (0xfc & (l>>18));
- ys[2] = (0xfc & (l>>12));
- ys[3] = (0xfc & (l>>6));
- u = (char)l;
- v = *data++;
- u<<=2;
- v<<=2;
- y = ys[0];
- WRITEPIXEL_TAB;
- y = ys[1];
- WRITEPIXEL_TAB;
- lp += rowLongs - 2;
- y = ys[2];
- WRITEPIXEL_TAB;
- y = ys[3];
- WRITEPIXEL_TAB;
- lp -= rowLongs;
- }
- } else {
- while ( blen-- > 0 ) {
- l = MyEndian32(*(long *)data);
- data += sizeof(long);
- ys[0] = (0xfc & (l>>24));
- ys[1] = (0xfc & (l>>18));
- ys[2] = (0xfc & (l>>12));
- ys[3] = (0xfc & (l>>6));
- u = (char)l;
- v = *data++;
- u<<=2;
- v<<=2;
- y = ys[0];
- WRITEPIXEL;
- y = ys[1];
- WRITEPIXEL;
- lp += rowLongs - 2;
- y = ys[2];
- WRITEPIXEL;
- y = ys[3];
- WRITEPIXEL;
- lp -= rowLongs;
- }
- }
- }
-
- #endif // DECO_BUILD
-
- #endif // NOASM
-
-
- #ifdef LINK_EXAMPLE_CODEC
-
- void InstallExampleCodec(void);
- void InstallExampleCodec(void)
-
- {
-
- ComponentDescription td;
- Component c;
- Handle cname;
- Handle dname;
-
- #if COMP_BUILD
- cname = NewHandle(13);
- td.componentType = OSTypeConst('imco');
- td.componentSubType = OSTypeConst('exmp');
- td.componentManufacturer = OSTypeConst('appl');
- td.componentFlags = codecInfoDoes32;
- td.componentFlagsMask = 0;
-
- BlockMoveData("\pTEST EX COMP",*cname,13);
- if ((c= RegisterComponent(&td,NewComponentRoutineProc(EXAMPLECODEC), 0,cname,nil, nil)) == 0 ) {
- Debugger();
- ExitToShell();
- }
- SetDefaultComponent(c,defaultComponentAnyManufacturer+defaultComponentAnyFlags);
- #endif
-
- #if DECO_BUILD
- dname = NewHandle(13);
- td.componentType = OSTypeConst('imdc');
- td.componentSubType = OSTypeConst('exmp');
- td.componentManufacturer = OSTypeConst('appl');
- td.componentFlags = codecInfoDoes32;
- td.componentFlagsMask = 0;
-
- BlockMoveData("\pTEST EX DECO",*dname,13);
- if ((c= RegisterComponent(&td,NewComponentRoutineProc(EXAMPLECODEC), 0,dname,nil, nil)) == 0 ) {
- Debugger();
- ExitToShell();
- }
- SetDefaultComponent(c,defaultComponentAnyManufacturer+defaultComponentAnyFlags);
- #endif
- }
- #endif
-
- #if QT_MP && ASYNC_DECODE
-
- Boolean TestBusy( Globals *glob )
- {
- ComponentMPWorkFunctionHeaderRecord work;
-
- // give the MP stuff a chance to call completion routines, schedule, and whatever
- work.headerSize = sizeof(ComponentMPWorkFunctionHeaderRecord);
- work.recordSize = sizeof(ComponentMPWorkFunctionHeaderRecord);
- work.isRunning = false;
- work.workFlags = mpWorkFlagGetIsRunning;
-
- if (glob->decompressFunction)
- CallComponentMPWorkFunctionProc(glob->decompressFunction, glob->decompressFunctionRefCon, &work);
-
- return glob->decompressCount != 0;
- }
-
- #endif
-